package nodeconv

import (
	"encoding/json"
	"log"
	"os"
	"sort"
	"strings"
)

// 算子组件
type Module struct {
	ID        string `json:"oiId"`
	Name      string `json:"oiName"`
	Sysmbol   string `json:"oiSymbol"`
	Status    int    `json:"oiStatus"` //输出算子
	Desc      string `json:"oiDesc"`
	In        string `json:"inDesc"`
	Out       string `json:"outDesc"`
	ModelID   string `json:"otId"` //模块类型 1 输入 2 输出 3 逻辑运算 4 算术运算
	ModelName string `json:"otName"`
}

func (m *Module) ToNode() (node *XNode) {
	node = new(XNode)
	node.ID = m.ID
	node.Width = 80
	node.Height = 22
	node.Label = m.Sysmbol
	node.Desc = m.Desc
	node.Data = map[string]any{
		"model":   m.ModelName,
		"name":    m.Name,
		"modelId": m.ModelID,
		"sysmbol": m.Sysmbol,
		"id":      m.ID,
	}
	in := ToPort(m.In, 0)
	out := ToPort(m.Out, node.Width)
	switch m.ModelID {
	case "1", "2":
		node.Width = 100
		node.Shape = "op-rect-io"

		if m.ModelID == "1" {
			for _, port := range out {
				port.Group = "in" //输入
				port.Attrs.Text.Text = ""
			}
			node.Ports = out
		} else {
			for _, port := range in {
				port.Group = "out" //输出
				port.Attrs.Text.Text = ""
			}
			node.Ports = in
		}
	default:
		node.Shape = "op-rect"
		max := len(in)
		if max < len(out) {
			max = len(out)
		}
		node.Height = 2 + max*20

		node.Ports = in
		node.Ports = append(node.Ports, out...)
	}
	return node
}

type Param struct {
	DataType     string `json:"dataType"`
	Desc         string `json:"description"`
	Index        int    `json:"index"`
	DefaultValue string `json:"dv"` //默认值
	IsShow       bool   `json:"isShow"`
	Name         string `json:"name"`
}

func NewParam(name, dataType, desc string, hide ...bool) *Param {
	p := new(Param)
	p.Name = name
	p.DataType = dataType
	p.Desc = desc
	if !(len(hide) > 0 && hide[0]) {
		p.IsShow = true
	}
	return p
}

func ToPort(data string, x int) (ports []*XPort) {
	data = strings.ReplaceAll(data, `\"`, `"`)
	var params []*Param
	json.Unmarshal([]byte(data), &params)
	i := 0
	for _, param := range params {
		if !param.IsShow {
			continue
		}
		port := new(XPort)
		port.Group = "in"
		// port.Args.X = x
		// port.Args.Y = y + i*20
		port.Attrs.Text.Text = param.Name
		kind := "in"
		if x != 0 {
			port.Group = "out"
			kind = "out"
		}
		port.Data = map[string]any{
			"name":     param.Name,
			"kind":     kind, //in or out
			"desc":     param.Desc,
			"dataType": param.DataType,
			"dv":       param.DefaultValue,
		} //param.DataType
		ports = append(ports, port)
		i++
	}
	return
}

type XNode struct {
	ID     string         `json:"id"`
	Shape  string         `json:"shape"`
	Desc   string         `json:"desc"`
	X      int            `json:"x"`
	Y      int            `json:"y"`
	Width  int            `json:"width"`
	Height int            `json:"height"`
	Label  string         `json:"label"`
	Data   map[string]any `json:"data"`
	Ports  []*XPort       `json:"ports"`
}

type XPort struct {
	Group string `json:"group"`
	//Args  Args           `json:"args"`
	Attrs Attrs          `json:"attrs"`
	Data  map[string]any `json:"data"`
}

// type Args struct {
// 	X int `json:"x"`
// 	Y int `json:"y"`
// }

type Attrs struct {
	Text Text `json:"text"`
}

type Text struct {
	Text string `json:"text"`
}

func MakeNodes(src, dest string) {
	var onodes []*Module
	var nodes []*XNode
	mp := map[string]*Module{}

	data, err := os.ReadFile(src)
	if err != nil {
		log.Println(err)
		return
	}
	err = json.Unmarshal(data, &onodes)
	if err != nil {
		log.Println(err)
		return
	}

	sort.Slice(onodes, func(i, j int) bool {
		if onodes[i].ModelID < onodes[j].ModelID {
			return true
		}
		return onodes[i].Name < onodes[j].Name
	})

	for _, onode := range onodes {
		_, ok := mp[onode.Sysmbol]
		if ok {
			continue
		}
		mp[onode.Sysmbol] = onode
		node := onode.ToNode()
		nodes = append(nodes, node)
	}

	data, err = json.Marshal(nodes)
	if err != nil {
		log.Println(err)
		return
	}

	//log.Println(string(data))
	os.WriteFile(dest, data, 0755)
}
